home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Freeware 1998 June
/
SGI Freeware 1998 June.iso
/
dist
/
fw_ATxgopher.idb
/
usr
/
freeware
/
src
/
xgopher.1.3
/
text.c.z
/
text.c
Wrap
C/C++ Source or Header
|
1998-01-21
|
19KB
|
852 lines
/* text.c
make and manage the text popups */
/*---------------------------------------------------------------*/
/* Xgopher version 1.3 08 April 1993 */
/* version 1.2 20 November 1992 */
/* version 1.1 20 April 1992 */
/* version 1.0 04 March 1992 */
/* X window system client for the University of Minnesota */
/* Internet Gopher System. */
/* Allan Tuchman, University of Illinois at Urbana-Champaign */
/* Computing and Communications Services Office */
/* Copyright 1992, 1993 by */
/* the Board of Trustees of the University of Illinois */
/* Permission is granted to freely copy and redistribute this */
/* software with the copyright notice intact. */
/*---------------------------------------------------------------*/
#include <stdio.h>
/* #include <sys/file.h> */ /* now comes from osdep.h */
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Viewport.h>
#include <X11/Shell.h>
#include "compatR4.h"
#if XtSpecificationRelease > 5
#define XGOPHER_X11R6 /* KeySink widget won't compile under R6 yet */
#else
#include "KeyWSink.h" /* KeySink works fine for R4 & R5 */
#endif
#include "conf.h"
#include "osdep.h"
#include "appres.h"
#include "xglobals.h"
#include "text.h"
#include "misc.h"
#include "subst.h"
#include "gopher.h"
#include "item.h"
#define PERCENT '%'
typedef struct _subItem {
char title[USER_STRING_LEN];
char host[HOST_STRING_LEN];
} subItem;
typedef struct _textElement {
Widget textShell;
Widget textDisplay;
int seqNumber;
TextClass class;
subItem origFields;
Boolean used;
Boolean hold;
Boolean deleteFile;
char *displayedFile;
char **wordList;
char *stringValue;
struct _textElement *next;
} textElement, *textElementP;
static textElementP textElementHead = NULL;
static textSeqNumber = 0;
#define THIS_POPUP_NAME "textPopup"
/* default values */
static popupPosResources placement = {
/* position at the top of the main panel, centered across */
from_none, 0, 0, justify_top_left, justify_top_left, False, False
};
/* textStringToFile
if a text widget has a string, rather than file value, copy the
string to a file, and set the structure to reflect this so things
will be cleaned up. */
static Boolean
textStringToFile(tep)
textElementP tep;
{
char *tempfile = XtMalloc(sizeof(char) * PATH_NAME_LEN);
FILE *fp;
getTempFile(tempfile);
if ((fp = fopen (tempfile, "w")) == NULL) {
return False;
}
fwrite (tep->stringValue, sizeof(char),
strlen(tep->stringValue), fp);
fclose(fp);
tep->displayedFile = tempfile;
tep->deleteFile = True;
free(tep->stringValue); /* free(), not XtFree() */
tep->stringValue = NULL;
return True;
}
/* pageDownProc
scroll down a page in a text widget */
void
pageDownProc(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
Widget tw = (Widget) client_data;
XtCallActionProc(tw, "next-page", NULL, NULL, 0);
}
/* pageUpProc
scroll up a page in a text widget */
void
pageUpProc(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
Widget tw = (Widget) client_data;
XtCallActionProc(tw, "previous-page", NULL, NULL, 0);
}
/* holdProc
hold the text window up, possibly overriding the concurrentText resource. */
void
holdProc(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
textElementP tep = (textElementP) client_data;
tep->hold = True;
}
/* printProc
send the contents of a text widget to the printer */
void
printProc(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
textElementP tep = (textElementP) client_data;
char *fileName;
char *printCommand;
char errorMessage[MESSAGE_STRING_LEN];
char *out, *in, *f;
Boolean hasFile = False;
gopherItemP fakeGI;
if (! appResources->allowPrint) {
return;
}
if (tep->displayedFile == NULL) {
if (! textStringToFile(tep) ) {
showError(
"Text cannot be printed because a temporary file cannot be created.");
return;
}
}
fakeGI = newItem();
strcpy(fakeGI->host, tep->origFields.host);
strcpy(USER_STRING(fakeGI), tep->origFields.title);
fakeGI->port = 0;
fileName = tep->displayedFile;
printCommand = editCommand(fakeGI, appResources->printCommand,
fileName, fileName);
if (system(printCommand) == 127) {
sprintf (errorMessage,
"The print command could not be executed:\n%s",
printCommand);
showError(errorMessage);
}
freeItem(fakeGI);
free(printCommand);
return;
}
/* saveDisplayedText
copy a displayed text file to a user-specified file obtained from the
file-save popup. This routine is a callback to that popup. */
BOOLEAN
saveDisplayedText(outFD, clientData)
int outFD;
XtPointer clientData;
{
textElementP tep = (textElementP) clientData;
int inFD;
if (tep->displayedFile == NULL) {
write( outFD, tep->stringValue,
sizeof(char)*strlen(tep->stringValue) );
} else {
if ((inFD = open(tep->displayedFile, O_RDONLY, 0)) < 0) {
showError( "Problem saving text file" );
return FALSE;
}
{
#define BUF_SZ 1024
char buf[BUF_SZ];
int cc;
cc = read(inFD, buf, BUF_SZ);
while (cc > 0) {
(void) write(outFD, buf, cc);
cc = read(inFD, buf, BUF_SZ);
}
if (cc < 0) {
close(inFD);
return FALSE;
}
}
}
close (inFD);
return TRUE;
}
/* saveProc
save the contents of a text widget to a file */
void
saveProc(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
textElementP tep = (textElementP) client_data;
if (tep == NULL) return;
if (! appResources->allowSave) {
return;
}
saveRequest( tep->textShell, (XtPointer) tep);
}
/* freeTextResources
free all resources associated with a textElement structure. */
static void
freeTextResources(tep)
textElementP tep;
{
if (tep->deleteFile)
if (unlink(tep->displayedFile) != 0) {
fprintf (stderr,
"Warning: a gopher internal file could not be removed.\n");
fprintf (stderr,
" This may indicate a system error.\n");
}
if (tep->displayedFile != NULL) {
XtFree(tep->displayedFile);
tep->displayedFile = NULL;
}
freeWordList(tep->wordList);
tep->wordList = NULL;
tep->deleteFile = False;
if (tep->stringValue != NULL) {
free(tep->stringValue); /* free(), not XtFree() */
}
tep->stringValue = NULL;
#ifdef XGOPHER_X11R4
/* the following should not be necessary, but some R4 versions
seem to not really free their string value! */
{
Cardinal n;
Arg args[3];
n = 0;
XtSetArg(args[n], XtNtype, XawAsciiString); n++;
XtSetArg(args[n], XtNstring, ""); n++;
XtSetValues(tep->textDisplay, args, n);
}
#endif /* XGOPHER_X11R4 */
}
/* doneProc
Done showing text file in a popup, clean up */
void
doneProc(w, client_data, call_data)
Widget w;
XtPointer client_data, call_data;
{
int i;
textElementP tep = (textElementP) client_data;
if (tep == NULL) return;
XtPopdown(tep->textShell);
freeTextResources(tep);
tep->used = False;
return;
}
/* cleanUpTextProc
Allow a final chance to remove all the temp files text knows about. */
void
cleanUpTextProc()
{
textElementP tep;
for (tep=textElementHead; tep != NULL; tep = tep->next)
if (tep->used && tep->deleteFile)
(void) unlink(tep->displayedFile);
return;
}
/* RemoveText
handle a done action specified via a translation.
Capitalization is for X convention. */
static void
RemoveText(w, event, params, numParams)
Widget w;
XEvent *event;
String *params;
Cardinal *numParams;
{
Widget button;
textElementP tep;
/* need the widget id of the Done button for that particular
text window. */
button = XtNameToWidget(w, "*textDone");
XtCallCallbacks(button, XtNcallback, NULL);
}
/* removeAllText
invoke the "done" callback for each text window displayed */
void
removeAllText()
{
textElementP tep;
for (tep=textElementHead; tep != NULL; tep = tep->next)
if (tep->used)
doneProc(tep->textShell, tep, NULL);
return;
}
/* createTextShell
Build a text popup */
static textElementP
createTextShell(topLevel)
Widget topLevel;
{
Widget doneButton, pageDownButton, pageUpButton,
printButton, saveButton, holdButton;
Widget buttonBox, textForm;
Arg args[10];
Cardinal n;
int i, w, h;
textElementP tep;
Widget kwSink;
static Boolean actionsAdded=False;
static XtActionsRec actionsTable[] = {
{"removeText", RemoveText}
};
if (!actionsAdded) {
XtAppAddActions(appcon, actionsTable, XtNumber(actionsTable));
actionsAdded = True;
/* find the popup placement for this shell */
{
popupPosResources *resourcePlacement;
resourcePlacement = getPopupPosResources(
THIS_POPUP_NAME, POPUP_POS_CLASS, &placement);
bcopy( (char *) resourcePlacement, (char *) &placement,
sizeof(popupPosResources) );
}
}
if ((tep = (textElementP) malloc(sizeof(textElement))) == NULL) {
showError("Too many windows are already open to show this file.");
return NULL;
}
tep->next = textElementHead;
textElementHead = tep;
/* create TEXT display popup */
n=0;
XtSetArg(args[n], XtNtitle, "Gopher Text"); n++;
/*
XtSetArg(args[n], XtNiconName, "Gopher Text"); n++;
*/
tep->textShell = XtCreatePopupShell("textShell",
topLevelShellWidgetClass,
topLevel, args, n);
/* create TEXT FORM */
n=0;
textForm = XtCreateManagedWidget("textForm", formWidgetClass,
tep->textShell, args, n);
/* create BUTTON BOX */
n=0;
XtSetArg(args[n], XtNorientation, XtorientHorizontal); n++;
XtSetArg(args[n], XtNtop, XawChainTop); n++;
XtSetArg(args[n], XtNbottom, XawChainTop); n++;
XtSetArg(args[n], XtNleft, XawChainLeft); n++;
XtSetArg(args[n], XtNright, XawChainLeft); n++;
buttonBox = XtCreateManagedWidget("textButtonBox", boxWidgetClass,
textForm, args, n);
/* create TEXT display */
n=0;
XtSetArg(args[n], XtNstring, ""); n++;
XtSetArg(args[n], XtNeditType, XawtextRead); n++;
XtSetArg(args[n], XtNscrollVertical,
XawtextScrollWhenNeeded); n++;
XtSetArg(args[n], XtNfromVert, buttonBox); n++;
XtSetArg(args[n], XtNtop, XawChainTop); n++;
XtSetArg(args[n], XtNbottom, XawChainBottom); n++;
XtSetArg(args[n], XtNleft, XawChainLeft); n++;
XtSetArg(args[n], XtNright, XawChainRight); n++;
tep->textDisplay = XtCreateManagedWidget("textDisplay",
asciiTextWidgetClass,
textForm, args, n);
setTextWidgetSize(tep->textDisplay, 80, 24);
#ifndef XGOPHER_X11R6
/* add the key word sink */
{
#define TAB_COUNT 32 /* same as in AsciiText.c */
Widget kwSink;
int i, tabs[TAB_COUNT], tab;
kwSink = XtCreateWidget("kwSink",
keyWSinkObjectClass,
tep->textDisplay, args, n);
for (i=0, tab=0 ; i < TAB_COUNT ; i++)
tabs[i] = (tab += 8);
XawTextSinkSetTabs(kwSink, TAB_COUNT, tabs);
n=0;
XtSetArg(args[n], XtNtextSink, kwSink); n++;
XtSetValues(tep->textDisplay, args, n);
}
#endif
/* create DONE button */
n=0;
doneButton = XtCreateManagedWidget("textDone", commandWidgetClass,
buttonBox, args, n);
XtAddCallback(doneButton, XtNcallback,
doneProc, (XtPointer) tep);
/* create PAGE_DOWN button */
n=0;
#ifndef XGOPHER_X11R4
XtSetArg(args[n], XtNleftBitmap, pageDownPixmap); n++;
#endif
pageDownButton = XtCreateManagedWidget("textPageDown",
commandWidgetClass,
buttonBox, args, n);
XtAddCallback(pageDownButton, XtNcallback,
pageDownProc, (XtPointer) tep->textDisplay);
/* create PAGE_UP button */
n=0;
#ifndef XGOPHER_X11R4
XtSetArg(args[n], XtNleftBitmap, pageUpPixmap); n++;
#endif
pageUpButton = XtCreateManagedWidget("textPageUp", commandWidgetClass,
buttonBox, args, n);
XtAddCallback(pageUpButton, XtNcallback,
pageUpProc, (XtPointer) tep->textDisplay);
/* create PRINT button */
if (appResources->allowPrint) {
n=0;
printButton = XtCreateManagedWidget("textPrint",
commandWidgetClass,
buttonBox, args, n);
XtAddCallback(printButton, XtNcallback,
printProc, (XtPointer) tep);
}
/* create SAVE button */
if (appResources->allowSave) {
n=0;
saveButton = XtCreateManagedWidget("textSave",
commandWidgetClass,
buttonBox, args, n);
XtAddCallback(saveButton, XtNcallback,
saveProc, (XtPointer) tep);
}
/* create HOLD button */
if (appResources->concurrentText > 0 && appResources->allowHold) {
n=0;
holdButton = XtCreateManagedWidget("textHold",
commandWidgetClass,
buttonBox, args, n);
XtAddCallback(holdButton, XtNcallback,
holdProc, (XtPointer) tep);
}
setPopupGeometry(tep->textShell, &placement);
/* for ICCCM window manager protocol complience */
XtOverrideTranslations (tep->textShell,
XtParseTranslationTable ("<Message>WM_PROTOCOLS: removeText()"));
XtRealizeWidget(tep->textShell);
(void) XSetWMProtocols (XtDisplay(tep->textShell),
XtWindow(tep->textShell),
&wmDeleteAtom, 1);
return tep;
}
/* saveItemInfo
copy info from the original gopher item, if any, to internal fields. */
saveItemInfo(localItem, gi, title)
subItem *localItem;
gopherItemP gi;
char *title;
{
if (gi != (gopherItemP) NULL) {
strcpy (localItem->host, gi->host);
strcpy (localItem->title, USER_STRING(gi));
} else {
(localItem->host)[0] = NULLC;
strcpy (localItem->title, title);
}
}
/* getTextElement
find a free textElement structure or get a new one. */
static textElementP
getTextElement(topLevel, class)
Widget topLevel;
TextClass class;
{
textElementP tep = NULL, p, oldest;
int n;
if (appResources->commonText) class = defaultTextClass;
/* if concurrentText is set > 0, then we have to find
out how many of these displays are popped up and reuse the
oldest if necessary. */
if (appResources->concurrentText> 0) {
n=0;
oldest = textElementHead;
for (p=textElementHead; p!=NULL; p = p->next) {
if (!p->used) continue;
if (p->hold) continue;
if (p->class == class) {
n++;
if (p->seqNumber < oldest->seqNumber) {
oldest = p;
}
}
}
if (n >= appResources->concurrentText) {
tep = oldest;
freeTextResources(tep);
return tep;
}
}
for (tep=textElementHead; (tep!=NULL && tep->used); tep = tep->next);
if (tep == NULL) {
if ((tep = createTextShell(topLevel)) == NULL) {
return NULL;
}
}
tep->seqNumber = textSeqNumber++;
tep->class = class;
tep->hold = False;
return tep;
}
/* displayTempFile
Load a text popup with a temp file */
void
displayTempFile(topLevel, class, gi, title, fileName)
Widget topLevel;
TextClass class;
gopherItemP gi;
char *title;
char *fileName;
{
Arg args[10];
Cardinal n;
char *textFileName;
textElementP tep;
Widget kwSink;
tep = getTextElement(topLevel, class);
if ((textFileName = (char *) XtMalloc(strlen(fileName)+1)) ==
NULL) {
showError("Unable to allocate additional memory.");
return;
}
strcpy(textFileName, fileName);
tep->displayedFile = textFileName;
tep->deleteFile = True;
tep->used = True;
tep->wordList = NULL;
tep->stringValue = NULL;
saveItemInfo(&(tep->origFields), gi, title);
#ifndef XGOPHER_X11R6
/* set keyword resource in text sink */
n = 0;
XtSetArg(args[n], XtNtextSink, &kwSink); n++;
XtGetValues(tep->textDisplay, args, n);
n = 0;
XtSetArg(args[n], XtNwordList, NULL); n++;
XtSetValues(kwSink, args, n);
#endif
/* set title and file name */
n = 0;
XtSetArg(args[n], XtNtitle, tep->origFields.title); n++;
if (appResources->nameText) {
XtSetArg(args[n], XtNiconName, title); n++;
}
XtSetValues(tep->textShell, args, n);
n = 0;
XtSetArg(args[n], XtNtype, XawAsciiFile); n++;
XtSetArg(args[n], XtNstring, textFileName); n++;
XtSetValues(tep->textDisplay, args, n);
positionAPopup(tep->textShell, topLevel, &placement);
XtPopup(tep->textShell, XtGrabNone);
return;
}
/* displayIndexTempFile
Load a text popup with a temp file and index words for highlighting */
void
displayIndexTempFile(topLevel, class, gi, title, fileName, indexString)
Widget topLevel;
TextClass class;
gopherItemP gi;
char *title;
char *fileName;
char *indexString;
{
Arg args[10];
Cardinal n;
char *textFileName;
textElementP tep;
Widget kwSink;
tep = getTextElement(topLevel, class);
if ((textFileName = (char *) XtMalloc(strlen(fileName)+1)) ==
NULL) {
showError("Unable to allocate additional memory.");
return;
}
strcpy(textFileName, fileName);
tep->displayedFile = textFileName;
tep->deleteFile = True;
tep->used = True;
tep->stringValue = NULL;
saveItemInfo(&(tep->origFields), gi, title);
#ifndef XGOPHER_X11R6
/* set keyword resource in text sink */
n = 0;
XtSetArg(args[n], XtNtextSink, &kwSink); n++;
XtGetValues(tep->textDisplay, args, n);
n = 0;
if (indexString == NULL) {
tep->wordList = NULL;
XtSetArg(args[n], XtNwordList, NULL); n++;
} else {
tep->wordList = makeWordList(indexString);
XtSetArg(args[n], XtNwordList, tep->wordList); n++;
}
XtSetValues(kwSink, args, n);
#endif
/* set title and file name */
n = 0;
XtSetArg(args[n], XtNtitle, tep->origFields.title); n++;
if (appResources->nameText) {
XtSetArg(args[n], XtNiconName, title); n++;
}
XtSetValues(tep->textShell, args, n);
n = 0;
XtSetArg(args[n], XtNtype, XawAsciiFile); n++;
XtSetArg(args[n], XtNstring, textFileName); n++;
XtSetValues(tep->textDisplay, args, n);
positionAPopup(tep->textShell, topLevel, &placement);
XtPopup(tep->textShell, XtGrabNone);
return;
}
/* displayTextString
Load a text popup with the contents of a text string */
void
displayTextString(topLevel, class, gi, title, string)
Widget topLevel;
TextClass class;
gopherItemP gi;
char *title;
char *string;
{
Arg args[10];
Cardinal n;
textElementP tep;
Widget kwSink;
tep = getTextElement(topLevel, class);
tep->displayedFile = NULL;
tep->deleteFile = False;
tep->used = True;
tep->wordList = NULL;
tep->stringValue = string;
saveItemInfo(&(tep->origFields), gi, title);
#ifndef XGOPHER_X11R6
/* set keyword resource in text sink */
n = 0;
XtSetArg(args[n], XtNtextSink, &kwSink); n++;
XtGetValues(tep->textDisplay, args, n);
n = 0;
XtSetArg(args[n], XtNwordList, NULL); n++;
XtSetValues(kwSink, args, n);
#endif
/* set title and file name */
n = 0;
XtSetArg(args[n], XtNtitle, tep->origFields.title); n++;
if (appResources->nameText) {
XtSetArg(args[n], XtNiconName, title); n++;
}
XtSetValues(tep->textShell, args, n);
n = 0;
XtSetArg(args[n], XtNtype, XawAsciiString); n++;
XtSetArg(args[n], XtNstring, string); n++;
XtSetValues(tep->textDisplay, args, n);
positionAPopup(tep->textShell, topLevel, &placement);
XtPopup(tep->textShell, XtGrabNone);
return;
}